#pragma once
#include <iostream>
#include <queue>
#include <pthread.h>
#include <unistd.h>
#include "lockGuard.hpp"

using namespace std;

static int gDefaultCap = 5;
// #define INI_TX(mtx) pthread_mutex_init(&mtx, nullptr)
// #define INI_COND(cond) pthread_cond_init(&cond, nullptr)

template <class T>
class BlockQueue
{
private:
    bool isQueueEmpty()
    {
        return _bq.size() == 0;
    }
    bool isQueueFull()
    {
        return _bq.size() == _capacity;
    }

public:
    BlockQueue(int capacity = gDefaultCap)
        : _capacity(capacity)
    {
        pthread_mutex_init(&_mtx, nullptr);
        pthread_cond_init(&_Empty, nullptr);
        pthread_cond_init(&_Full, nullptr);
    }
    void push(const T &in) // 生产者
    {
        // pthread_mutex_lock(&_mtx);
        // // 1.检测临界资源
        // // if (isQueueFull())
        // while (isQueueFull()) // 保证临界资源一定就绪
        // {
        //     // 我们竟然是在临界区中!我是持有锁的!如果我去等待了，锁该怎么办呢
        //     // 第二个参数是一个锁，当成功调用wait之后，传入的锁，会被自动释放!
        //     // 唤醒时，从哪阻塞，从哪唤醒,并且自动获取锁
        //     pthread_cond_wait(&_Full, &_mtx);
        //     // pthread_cond_wait：是函数，可能调用失败
        //     // pthread_cond_wait：伪唤醒的情况
        // }
        // // 2.访问
        // _bq.push(in);
        //
        // if (_bq.size() >= _capacity / 2)
        //     pthread_cond_signal(&_Empty);
        //
        // pthread_mutex_unlock(&_mtx);
        lockGuard lockgruard(&_mtx);
        while (isQueueFull())
            pthread_cond_wait(&_Full, &_mtx);

        _bq.push(in);

        pthread_cond_signal(&_Empty);
        // 自动调用unlock
    }

    void pop(T *out)
    {
        // pthread_mutex_lock(&_mtx);
        lockGuard lockguard(&_mtx);
        // if (isQueueEmpty())
        while (isQueueEmpty())
        {
            pthread_cond_wait(&_Empty, &_mtx);
        }
        *out = _bq.front();
        _bq.pop();
        // pthread_mutex_unlock(&_mtx);

        pthread_cond_signal(&_Full);
    }
    ~BlockQueue()
    {
        pthread_mutex_destroy(&_mtx);
        pthread_cond_destroy(&_Empty);
        pthread_cond_destroy(&_Full);
    }

private:
    queue<T> _bq;
    int _capacity;         // 容量上限
    pthread_mutex_t _mtx;  // 互斥锁保证队列安全
    pthread_cond_t _Empty; // 阻塞队列是否为空
    pthread_cond_t _Full;  // 阻塞队列是否满了
};